home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
scheme
/
boxer
/
boxer.lha
/
numbrs.lisp
< prev
next >
Wrap
Text File
|
1993-07-17
|
14KB
|
522 lines
;;; -*- Mode:LISP; Package:(BOXER GLOBAL 1000); Base:10.; Fonts:CPTFONT -*-
;;; (C) Copyright 1985 Massachusetts Institute of Technology
;;;
;;; Permission to use, copy, modify, distribute, and sell this software
;;; and its documentation for any purpose is hereby granted without fee,
;;; provided that the above copyright notice appear in all copies and that
;;; both that copyright notice and this permission notice appear in
;;; supporting documentation, and that the name of M.I.T. not be used in
;;; advertising or publicity pertaining to distribution of the software
;;; without specific, written prior permission. M.I.T. makes no
;;; representations about the suitability of this software for any
;;; purpose. It is provided "as is" without express or implied warranty.
;;;
;;;constants
#-ti(defconst PI 3.14592653) ;already defined by TI
(defconst pi)
(defconst TO-DEGREES (// 180 pi))
(defboxer-function bu: () )
(defboxer-function bu:pi () PI)
;;; What the evaluator understands as logical values
(EVAL-WHEN (LOAD)
(SHADOW '(TRUE FALSE) 'BOXER)
)
(DEFCONST TRUE 'BU:TRUE)
(DEFCONST FALSE 'BU:FALSE)
(DEFUN TRUE () TRUE)
(DEFUN FALSE () FALSE)
;;; useful to have around for comparing things
(DEFCONST TRUE-EVBOX (MAKE-EVDATA ROWS `(,(MAKE-EVROW-FROM-ENTRY 'BU:TRUE))))
(DEFCONST FALSE-EVBOX (MAKE-EVDATA ROWS `(,(MAKE-EVROW-FROM-ENTRY 'BU:FALSE))))
;;; Variables for modifying data box arithmetic behavior
(DEFVAR *NON-MATCHING-BOX-ARITHMETIC-ACTION* ':ERROR
"Specifies how to handle situations when the args to arithmetic operations have
differing numbers of elements. Currently allowed values are :ERROR (signal an error),
:FILL (fill smaller boxes with zeros), and :TRUNCATE (ignore extra elements in the larger
boxes). ")
;;; is it live, or is it a number
(DEFBOXER-FUNCTION BU:NUMBER? (THING)
(BOXER-BOOLEAN (BOXER-NUMBER? THING)))
(DEFUN BOXER-NUMBER? (THING)
(OR (NUMBERP THING)
(NUMBER-BOX? THING)))
;;; Generic operation macros
(DEFUN TYPIFY-ARGS (&REST ARGS)
"Returns :NUMBER if all the args are numbers or :BOX if ANY arg is a box or NIL"
(IF (NULL (SUBSET #'(LAMBDA (X) (OR (EVAL-BOX? X) (EVAL-PORT? X))) ARGS))
':NUMBER
':BOX))
(DEFMACRO ARG-DISPATCH (OP . ARGS)
`(SELECTQ (TYPIFY-ARGS ,@ARGS)
((:BOX)
;; at least one arg is a box so use the box arithmetic routines
(FUNCALL ',(INTERN (STRING-APPEND "DATA-BOX-" (STRING `,OP))) ,@ARGS))
((:NUMBER)
;; assume that all the args are numbers (may want to put an error check here)
(FUNCALL ',OP ,@ARGS))
(OTHERWISE
(FERROR "The args, ~A, to ~A were not boxes or numbers" (LIST ,@ARGS) ',OP))))
(DEFMETHOD (BOX :ELEMENTS) ()
(LOOP FOR ROW IN (TELL SELF :ROWS)
APPENDING (TELL ROW :ELEMENTS)))
;;; Boxer versions of some operators (the others we import directly)
(DEFUN BOXER-> (A B)
(BOXER-BOOLEAN
(COND ((> A B) t)
(T NIL))))
(DEFUN BOXER-< (A B)
(BOXER-BOOLEAN
(COND ((< A B) t)
(T NIL))))
(DEFUN BOXER- (A B)
(BOXER-BOOLEAN
(COND (( A B) t)
(T NIL))))
(DEFUN BOXER- (A B)
(BOXER-BOOLEAN
(COND (( A B) t)
(T NIL))))
(DEFUN BOXER->= (A B)
(BOXER-BOOLEAN
(COND ((>= A B) t)
(T NIL))))
(DEFUN BOXER-<= (A B)
(BOXER-BOOLEAN
(COND ((<= A B) t)
(T NIL))))
(DEFUN BOXER-QUOTIENT (divisor dividend)
(//$ (float divisor) (float dividend)))
(DEFUN BOXER-EXPT (A B)
(if (and (minusp a)
(floatp b)
(zerop (- b (fix b))))
(expt a (fix b))
(expt a b)))
; (IF (AND (TYPEP A ':FIX) (TYPEP B ':FIX))
; (^ A B)
; (^$ (FLOAT A) (FLOAT B))))
(DEFUN BOXER-ATAN (Y X)
(* (ATAN Y X) TO-DEGREES))
(DEFUN BOXER-ZERO? (N)
(BOXER-BOOLEAN (ZEROP N)))
(DEFUN BOXER-PLUS? (N)
(BOXER-BOOLEAN (PLUSP N)))
(DEFUN BOXER-MINUS? (N)
(BOXER-BOOLEAN (MINUSP N)))
(DEFUN BOXER-ODD? (N)
(BOXER-BOOLEAN (when (fixp n) (ODDP N))))
(DEFUN BOXER-EVEN? (N)
(BOXER-BOOLEAN (when (fixp n)(EVENP N))))
;;; Data box arithmetic
(DEFUN COMPARE-BOX-LENGTHS (&REST BOXES)
(LOOP WITH SAME-LENGTH = T
WITH CURRENT-LENGTH = (GET-BOX-LENGTH-IN-ROWS (CAR BOXES))
FOR BOX IN BOXES
FOR LENGTH = (GET-BOX-LENGTH-IN-ROWS BOX)
UNLESS (= LENGTH CURRENT-LENGTH)
DO (SETQ SAME-LENGTH NIL)
MINIMIZE LENGTH INTO SMALLEST-LENGTH
MAXIMIZE LENGTH INTO LARGEST-LENGTH
DO (SETQ CURRENT-LENGTH LENGTH)
FINALLY (RETURN (VALUES SAME-LENGTH SMALLEST-LENGTH LARGEST-LENGTH))))
(DEFUN COMPARE-ROW-LENGTHS (&REST ROWS)
(LOOP WITH CURRENT-LENGTH = (LENGTH (CAR ROWS))
FOR ROW IN (CDR ROWS)
FOR LENGTH = (LENGTH ROW)
WHEN ( LENGTH CURRENT-LENGTH)
RETURN NIL
FINALLY (RETURN T)))
(DEFUN COLLECT-NTHS (N LISTS)
(LOOP FOR LIST IN LISTS
COLLECTING (NTH N LIST)))
(DEFUN MAP-OVER-ROW-ELEMENTS (FCN ROWS)
(MAKE-EVROW-FROM-ENTRIES
(SELECTQ *NON-MATCHING-BOX-ARITHMETIC-ACTION*
((:TRUNCATE) (LEXPR-FUNCALL #'MAPCAR FCN ROWS))
((:FILL)
(LOOP FOR INDEX FROM 0 TO (1- (LEXPR-FUNCALL #'MAX (MAPCAR #'LENGTH ROWS)))
COLLECTING (APPLY FCN (MAPCAR #'(LAMBDA (X) (OR (NTH INDEX X) 0)) ROWS))))
(OTHERWISE (IF (LEXPR-FUNCALL #'COMPARE-ROW-LENGTHS ROWS)
(LEXPR-FUNCALL #'MAPCAR FCN ROWS)
(FERROR "The rows, ~A have different numbers of elements" ROWS))))))
(DEFUN MAP-OVER-BOXS-ELEMENTS (FCN BOXES)
"Mapping function for functions with mutiple box arguments"
(LET ((ROWS (MULTIPLE-VALUE-BIND (SAME-SIZE MIN-SIZE MAX-SIZE)
(LEXPR-FUNCALL #'COMPARE-BOX-LENGTHS BOXES)
(SELECTQ *NON-MATCHING-BOX-ARITHMETIC-ACTION*
((:TRUNCATE)
(LOOP WITH ROWS-LISTS = (MAPCAR #'GET-BOX-ROWS BOXES)
FOR INDEX FROM 0 TO (1- MIN-SIZE)
FOR ROWS = (COLLECT-NTHS INDEX ROWS-LISTS)
COLLECTING (MAP-OVER-ROW-ELEMENTS FCN ROWS)))
((:FILL)
(LOOP WITH ROWS-LISTS = (MAPCAR #'GET-BOX-ROWS BOXES)
FOR INDEX FROM 0 TO (1- MAX-SIZE)
FOR ROWS = (COLLECT-NTHS INDEX ROWS-LISTS)
COLLECTING (MAP-OVER-ROW-ELEMENTS FCN ROWS)))
(OTHERWISE
(IF (NULL SAME-SIZE)
(FERROR "The boxes ,~A have different numbers of rows" BOXES)
(LOOP WITH ROWS-LISTS = (MAPCAR #'GET-BOX-ROWS BOXES)
FOR INDEX FROM 0 TO (1- MIN-SIZE)
FOR ROWS = (COLLECT-NTHS INDEX ROWS-LISTS)
COLLECTING (MAP-OVER-ROW-ELEMENTS FCN ROWS))))))))
(IF (AND (= 1 (LENGTH ROWS)) (= 1 (EVROW-LENGTH-IN-ELEMENTS (CAR ROWS)))
(NUMBERP (GET-FIRST-ELEMENT-IN-EVROW (CAR ROWS))))
;;we flatten boxes with single numbers in them into the numbers
(GET-FIRST-ELEMENT-IN-EVROW (CAR ROWS))
(MAKE-EVDATA ROWS ROWS))))
(DEFUN MAP-OVER-BOX-ELEMENTS (FCN BOX)
"Mapping-function for functions which take only a single box argument. "
(LET ((ROWS (LOOP FOR ROW IN (GET-BOX-ROWS BOX)
COLLECTING (MAKE-EVROW-FROM-ENTRIES (MAPCAR FCN ROW)))))
(IF (AND (= 1 (LENGTH ROWS)) (= 1 (EVROW-LENGTH-IN-ELEMENTS (CAR ROWS)))
(NUMBERP (GET-FIRST-ELEMENT-IN-EVROW (CAR ROWS))))
;;we flatten boxes with single numbers in them into the numbers
(GET-FIRST-ELEMENT-IN-EVROW (CAR ROWS))
(MAKE-EVDATA ROWS ROWS))))
;;; Multiple data box argument functions
(DEFUN DATA-BOX-PLUS (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'PLUS BOXES))
(DEFUN DATA-BOX-DIFFERENCE (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'DIFFERENCE BOXES))
(DEFUN DATA-BOX-TIMES (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'TIMES BOXES))
(DEFUN DATA-BOX-BOXER-QUOTIENT (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-QUOTIENT BOXES))
(DEFUN DATA-BOX-REMAINDER (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'REMAINDER BOXES))
(DEFUN DATA-BOX-BOXER-EXPT (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-EXPT BOXES))
(DEFUN DATA-BOX-BOXER-ATAN (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-ATAN BOXES))
(DEFUN DATA-BOX-GCD (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'GCD BOXES))
(DEFUN DATA-BOX-MAX (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'MAX BOXES))
(DEFUN DATA-BOX-MIN (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'MIN BOXES))
(DEFUN DATA-BOX-BOXER-> (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-> BOXES))
(DEFUN DATA-BOX-BOXER-< (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-< BOXES))
(DEFUN DATA-BOX-BOXER- (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER- BOXES))
(DEFUN DATA-BOX-BOXER- (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER- BOXES))
(DEFUN DATA-BOX-BOXER->= (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER->= BOXES))
(DEFUN DATA-BOX-BOXER-<= (&REST BOXES)
(MAP-OVER-BOXS-ELEMENTS #'BOXER-<= BOXES))
;;; Functions which take a single data box argument
;;; single argument predicates
(DEFUN DATA-BOX-BOXER-MINUS? (BOX)
(MAP-OVER-BOX-ELEMENTS #'BOXER-MINUS? BOX))
(DEFUN DATA-BOX-BOXER-PLUS? (BOX)
(MAP-OVER-BOX-ELEMENTS #'BOXER-PLUS? BOX))
(DEFUN DATA-BOX-BOXER-ZERO? (BOX)
(MAP-OVER-BOX-ELEMENTS #'BOXER-ZERO? BOX))
(DEFUN DATA-BOX-BOXER-EVEN? (BOX)
(MAP-OVER-BOX-ELEMENTS #'BOXER-EVEN? BOX))
(DEFUN DATA-BOX-BOXER-ODD? (BOX)
(MAP-OVER-BOX-ELEMENTS #'BOXER-ODD? BOX))
;;; single argument other stuff
(DEFUN DATA-BOX-SIND (BOX)
(MAP-OVER-BOX-ELEMENTS #'SIND BOX))
(DEFUN DATA-BOX-COSD (BOX)
(MAP-OVER-BOX-ELEMENTS #'COSD BOX))
(DEFUN DATA-BOX-RANDOM (BOX)
(MAP-OVER-BOX-ELEMENTS #'RANDOM BOX))
(DEFUN DATA-BOX-ABS (BOX)
(MAP-OVER-BOX-ELEMENTS #'ABS BOX))
(DEFUN DATA-BOX-SQRT (BOX)
(MAP-OVER-BOX-ELEMENTS #'SQRT BOX))
(DEFUN DATA-BOX-EXP (BOX)
(MAP-OVER-BOX-ELEMENTS #'EXP BOX))
(DEFUN DATA-BOX-LOG (BOX)
(MAP-OVER-BOX-ELEMENTS #'LOG BOX))
(DEFUN DATA-BOX-ROUND (BOX)
(MAP-OVER-BOX-ELEMENTS #'ROUND BOX))
(DEFUN DATA-BOX-FLOOR (BOX)
(MAP-OVER-BOX-ELEMENTS #'FLOOR BOX))
(DEFUN DATA-BOX-CEILING (BOX)
(MAP-OVER-BOX-ELEMENTS #'CEILING BOX))
;;; LOGICAL and support functions
(DEFBOXER-FUNCTION BU:FALSE ()
FALSE)
(DEFBOXER-FUNCTION BU:TRUE ()
TRUE)
(defun boxer-boolean (t-or-nil)
(if t-or-nil TRUE FALSE))
;;; these are for internal use and return the values T or NIL (NOT TRUE or FALSE)
(defun TRUE? (true-or-false)
(when (eval-port? true-or-false) (setq true-or-false (get-port-target true-or-false)))
(COND ((EVAL-BOX? TRUE-OR-FALSE)
(BOX-EQUAL? TRUE-OR-FALSE TRUE-EVBOX))
(T (STRING-EQUAL TRUE-OR-FALSE TRUE))))
(defun FALSE? (true-or-false)
(when (eval-port? true-or-false) (setq true-or-false (get-port-target true-or-false)))
(COND ((EVAL-BOX? TRUE-OR-FALSE)
(box-equal? true-or-false FALSE-EVBOX))
(T (STRING-EQUAL TRUE-OR-FALSE FALSE))))
;;; The Boxer functions
(DEFBOXER-FUNCTION BU:NOT (TRUE-OR-FALSE)
(IF (TRUE? TRUE-OR-FALSE) FALSE TRUE))
(DEFUN BOXER-= (A B)
(COND ((AND (NUMBER-BOX? A) (NUMBER-BOX? B))
(= (NUMBERIZE A) (NUMBERIZE B)))
((OR (STRINGP A) (STRINGP B)) (EQUAL A B))
((OR (SYMBOLP A) (SYMBOLP B)) (EQUAL A B))
((AND (or (EVAL-BOX? A) (eval-port? a)) (or (EVAL-BOX? B) (eval-port? b)))
(BOX-EQUAL? A B))
(T NIL)))
(DEFBOXER-FUNCTION BU:= (A B)
(BOXER-BOOLEAN (BOXER-= A B)))
(DEFBOXER-FUNCTION BU: (A B)
(BOXER-BOOLEAN (NOT (BOXER-= A B))))
(DEFBOXER-FUNCTION BU:AND (A B)
(BOXER-BOOLEAN (AND (TRUE? A)
(TRUE? B))))
(DEFBOXER-FUNCTION BU:OR (A B)
(BOXER-BOOLEAN (OR (TRUE? A)
(TRUE? B))))
;;; And into Boxer we go....
;;; single argument predicates
(DEFBOXER-FUNCTION BU:PLUS? (X)
(arg-dispatch BOXER-PLUS? X))
(DEFBOXER-FUNCTION BU:MINUS? (X)
(arg-dispatch BOXER-MINUS? X))
(DEFBOXER-FUNCTION BU:ZERO? (X)
(ARG-DISPATCH BOXER-ZERO? X))
(DEFBOXER-FUNCTION BU:EVEN? (X)
(arg-dispatch BOXER-EVEN? X))
(DEFBOXER-FUNCTION BU:ODD? (X)
(arg-dispatch BOXER-ODD? X))
;;; single argument other stuff
(DEFBOXER-FUNCTION BU:CEILING (FLOAT)
(ARG-DISPATCH CEILING FLOAT))
(defboxer-function bu:round (float)
(arg-dispatch round float))
(defboxer-function bu:floor (float)
(arg-dispatch floor float))
(DEFBOXER-FUNCTION BU:MINUS (BOX)
(arg-dispatch BOXER-MINUS BOX))
(DEFBOXER-FUNCTION BU:RANDOM (LESS-THAN)
(arg-dispatch RANDOM LESS-THAN))
(DEFBOXER-FUNCTION BU:ABS (X)
(arg-dispatch ABS X))
(DEFBOXER-FUNCTION BU:SQRT (X)
(arg-dispatch SQRT X))
(DEFBOXER-FUNCTION BU:EXP (X)
(arg-dispatch EXP X))
(DEFBOXER-FUNCTION BU:LOG (X)
(arg-dispatch LOG X))
(DEFBOXER-FUNCTION BU:SIN (ANGLE)
(arg-dispatch SIND ANGLE))
(DEFBOXER-FUNCTION BU:COS (ANGLE)
(arg-dispatch COSD ANGLE))
;;; Two argument predicates
(DEFBOXER-FUNCTION BU:< (A B)
(arg-dispatch BOXER-< A B))
(DEFBOXER-FUNCTION BU:> (A B)
(arg-dispatch BOXER-> A B))
(DEFBOXER-FUNCTION BU: (A B)
(arg-dispatch BOXER- A B))
(DEFBOXER-FUNCTION BU: (A B)
(arg-dispatch BOXER- A B))
(DEFBOXER-FUNCTION BU:<= (A B)
(arg-dispatch BOXER-<= A B))
(DEFBOXER-FUNCTION BU:>= (A B)
(arg-dispatch BOXER->= A B))
;;; Two argument other stuff
(DEFBOXER-FUNCTION BU:PLUS (A B)
(arg-dispatch PLUS A B))
(DEFBOXER-FUNCTION BU:+ (A B)
(arg-dispatch PLUS A B))
(DEFBOXER-FUNCTION BU:DIFFERENCE (A B)
(arg-dispatch DIFFERENCE A B))
(DEFBOXER-FUNCTION BU:- (A B)
(arg-dispatch DIFFERENCE A B))
(DEFBOXER-FUNCTION BU:TIMES (A B)
(arg-dispatch TIMES A B))
(DEFBOXER-FUNCTION BU:* (A B)
(arg-dispatch TIMES A B))
(DEFBOXER-FUNCTION BU:QUOTIENT (A B)
(arg-dispatch BOXER-QUOTIENT A B))
(DEFBOXER-FUNCTION BU:// (A B)
(arg-dispatch BOXER-QUOTIENT A B))
(DEFBOXER-FUNCTION BU:REMAINDER (A B)
(arg-dispatch REMAINDER A B))
(DEFBOXER-FUNCTION BU:EXPT (A B)
(arg-dispatch BOXER-EXPT A B))
(DEFBOXER-FUNCTION BU:ATAN (A B)
(arg-dispatch BOXER-ATAN A B))
(DEFBOXER-FUNCTION BU:^ (A B)
(arg-dispatch BOXER-EXPT A B))
(DEFBOXER-FUNCTION BU:GCD (A B)
(arg-dispatch GCD A B))
(DEFBOXER-FUNCTION BU:MIN (A B)
(arg-dispatch MIN A B))
(DEFBOXER-FUNCTION BU:MAX (A B)
(ARG-DISPATCH MAX A B))
;;; rational stuff
(defun data-box-rational (a)
(map-over-box-elements #'rational a))
(defun data-box-float (a)
(map-over-box-elements #'float a))
(defun data-box-numerator (a)
(map-over-box-elements #'numerator a))
(defun data-box-denominator (a)
(map-over-box-elements #'denominator a))
(defboxer-function bu:rational (a)
(arg-dispatch rational a))
(defboxer-function bu:float (a)
(arg-dispatch float a))
(defboxer-function bu:numerator (a)
(arg-dispatch numerator a))
(defboxer-function bu:denominator (a)
(arg-dispatch denominator a))
(load "es://usr//emstsun//guest//load-box.lisp")